﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ApiProjectCreationTool.Code;

namespace ApiProjectCreationTool
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            textBox3.Text = Directory.GetParent(Directory.GetParent(Directory.GetParent(Application.StartupPath).FullName).FullName).FullName;
        }


        private void button1_Click(object sender, EventArgs e)
        {
            if (textBox1.Text.Trim().Length == 0)
            {
                MessageBox.Show("项目名称必填");
                return;
            }

            if (textBox2.Text.Trim().Length == 0)
            {
                MessageBox.Show("存放路径必填");
                return;
            }

            if (!IsDirectoryEmpty(textBox2.Text))
            {
                MessageBox.Show("存放路径必须为空文件夹!");
                return;
            }

            string projectName = FilterFileName(textBox1.Text.Trim());
            textBox1.Text = projectName.ToUpperInitial();

            //创建项目文件夹
            string projectPath = Path.Combine(textBox2.Text.Trim(), projectName);
            string entityPath = Path.Combine(projectPath, projectName + ".Entity");
            string modelPath = Path.Combine(projectPath, projectName + ".Model");
            string iServicePath = Path.Combine(projectPath, projectName + ".IService");
            string servicePath = Path.Combine(projectPath, projectName + ".Service");
            string apiPath = Path.Combine(projectPath, projectName + "Api");
            CreateDirectory(projectPath, "");
            CreateDirectory(entityPath);
            CreateDirectory(modelPath, "bin,obj,Config,DTO,Input,Output");
            CreateDirectory(iServicePath);
            CreateDirectory(servicePath);
            CreateDirectory(apiPath, "bin,Code,Configs,Controllers,obj,Properties,wwwroot");
            CreateDirectory(Path.Combine(projectPath, "BoYuanCore.Framework"), "bin,CoreMvc,Extensions,MemoryCache,Net,obj,StringUtility");
            CreateDirectory(Path.Combine(projectPath, "FreeSqlExtensions"), "bin,obj");

            //生成项目文件
            string basePath = textBox3.Text;
            string frameworkPath = Path.Combine(basePath, "BoYuanCore.Framework");
            string freeSqlExtensionsPath = Path.Combine(basePath, "FreeSqlExtensions");
            string entityPath2 = Path.Combine(basePath, "KeXin.Entity");
            string modelPath2 = Path.Combine(basePath, "KeXin.Model");
            string iServicePath2 = Path.Combine(basePath, "KeXin.IService");
            string servicePath2 = Path.Combine(basePath, "KeXin.Service");
            string apiPath2 = Path.Combine(basePath, "KeXinApi");

            CreateNewCode(frameworkPath, Path.Combine(projectPath, "BoYuanCore.Framework"), "BoYuanCore.Framework", projectName);
            CreateNewCode(frameworkPath, Path.Combine(projectPath, "BoYuanCore.Framework"), "BoYuanCore.Framework", projectName, "csproj");
            CreateNewCode(freeSqlExtensionsPath, Path.Combine(projectPath, "FreeSqlExtensions"), "FreeSqlExtensions", projectName);
            CreateNewCode(freeSqlExtensionsPath, Path.Combine(projectPath, "FreeSqlExtensions"), "FreeSqlExtensions", projectName, "csproj");
            CreateNewCode(entityPath2, entityPath, "KeXin.Entity", projectName);
            CreateNewCode(modelPath2, modelPath, "KeXin.Model", projectName);
            CreateNewCode(iServicePath2, iServicePath, "KeXin.IService", projectName);
            CreateNewCode(servicePath2, servicePath, "KeXin.Service", projectName);
            CreateNewCode(apiPath2, apiPath, "KeXinApi", projectName);
            CreateNewCode(apiPath2, apiPath, "KeXinApi", projectName, "json");
            ResetFile(apiPath2, apiPath,  projectName,"xml");
            ResetFile(apiPath2, apiPath,  projectName,"html");

            ResetFile(entityPath2, entityPath,  projectName, "csproj");
            ResetFile(modelPath2, modelPath,  projectName, "csproj");
            ResetFile(iServicePath2, iServicePath,  projectName, "csproj");
            ResetFile(servicePath2, servicePath,  projectName, "csproj");
            ResetFile(apiPath2, apiPath,  projectName, "csproj");

            //创建sln
            string result = CodeTemplate.GetSLN(projectName);
            File.WriteAllText(Path.Combine(projectPath, projectName + ".sln"), result, System.Text.Encoding.UTF8);

            MessageBox.Show("Api项目创建成功!");

        }

        private void button2_Click(object sender, EventArgs e)
        {
            // 显示对话框并检查用户是否点击了"确定"
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                // 使用选择的路径
                textBox2.Text = folderBrowserDialog1.SelectedPath;
            }

            if (!IsDirectoryEmpty(textBox2.Text))
            {
                MessageBox.Show("存放路径必须为空文件夹!");
            }
        }
        private void button3_Click(object sender, EventArgs e)
        {
            // 显示对话框并检查用户是否点击了"确定"
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                // 使用选择的路径
                textBox3.Text = folderBrowserDialog1.SelectedPath;
            }
        }


        /// <summary>
        /// 过滤文件名称，不允许有非法字符串
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static string FilterFileName(string fileName)
        {
            StringBuilder sb = new StringBuilder(fileName);
            sb.Replace(" ", "_");//服务器端文件名，不允许有空格
            sb.Replace("\\", "");
            sb.Replace("/", "");
            sb.Replace(":", "");
            sb.Replace("*", "");
            sb.Replace("?", "");
            sb.Replace("\"", "");
            sb.Replace("<", "");
            sb.Replace(">", "");
            sb.Replace("|", "");

            return sb.ToString();
        }

        /// <summary>
        /// 创建文件夹及子文件夹
        /// </summary>
        /// <param name="dirPath"></param>
        /// <param name="sonDirs">子文件夹</param>
        private void CreateDirectory(string dirPath, string sonDirs = "bin,obj,Base")
        {
            if (Directory.Exists(dirPath)) return;
            try
            {
                Directory.CreateDirectory(dirPath);
                if (!string.IsNullOrEmpty(sonDirs))
                {
                    //创建子文件夹
                    var sonPathList = sonDirs.Split(',');
                    foreach (var sp in sonPathList)
                    {
                        CreateDirectory(Path.Combine(dirPath, sp), "");
                    }
                }
            }
            catch
            {
                throw;
            }
        }

        /// <summary>
        /// 判断文件夹是否为空
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static bool IsDirectoryEmpty(string path)
        {
            if (!Directory.Exists(path))
            {
                return true;
            }

            // 使用 EnumerateFileSystemEntries 更高效
            return !Directory.EnumerateFileSystemEntries(path).Any();
        }

        /// <summary>
        /// 创建新项目代码
        /// </summary>
        /// <param name="oldCodePath">原文件地</param>
        /// <param name="newCodePath">新文件地址</param>
        /// <param name="replacePathKey">要替换的关键词</param>
        /// <param name="projectName">项目名称</param>
        /// <param name="fileExtension">要筛选的代码文件后缀名</param>
        private void CreateNewCode(string oldCodePath, string newCodePath, string replacePathKey, string projectName, string fileExtension = "cs")
        {
            var list = GetAllFilePaths(oldCodePath, fileExtension);
            foreach (var cs in list)
            {
                string tempPath = cs.Replace(replacePathKey + "\\", "|").Split('|')[1];
                CopyReplaceFile(cs, Path.Combine(newCodePath, tempPath), projectName);
            }
        }

        /// <summary>
        /// 重命名创建文件
        /// </summary>
        /// <param name="oldCodePath">原文件地</param>
        /// <param name="newCodePath">新文件地址</param>
        /// <param name="projectName">项目名称</param>
        private void ResetFile(string oldCodePath, string newCodePath, string projectName, string fileExtension)
        {
            var list = GetAllFilePaths(oldCodePath, fileExtension);//csproj ,  xml 等
            foreach (var cs in list)
            {
                string newFileName = Path.GetFileName(cs).Replace("KeXin", projectName);
                CopyReplaceFile(cs, Path.Combine(newCodePath, newFileName), projectName);
            }
        }


        /// <summary>
        /// 创建xml
        /// </summary>
        /// <param name="oldCodePath">原文件地</param>
        /// <param name="newCodePath">新文件地址</param>
        /// <param name="xmlName">新文件名称</param>
        /// <param name="projectName">项目名称</param>
        private void ResetXml(string oldCodePath, string newCodePath, string xmlName, string projectName)
        {
            var list = GetAllFilePaths(oldCodePath, "xml");
            foreach (var cs in list)
            {
                CopyReplaceFile(cs, Path.Combine(newCodePath, xmlName), projectName);
            }
        }

        /// <summary>
        /// 获取指定路径下的所有文件
        /// </summary>
        /// <param name="folderPath">路径</param>
        /// <param name="fileExtension">文件后缀名称(例如:txt)</param>
        /// <returns></returns>
        private static List<string> GetAllFilePaths(string folderPath, string fileExtension)
        {
            List<string> fileList = new List<string>();

            // 获取当前文件夹下的所有文件路径
            string[] txtFilePaths = Directory.GetFiles(folderPath, "*." + fileExtension);
            foreach (string filePath in txtFilePaths)
            {
                //排除obj和bin文件夹
                if (!filePath.Contains("\\obj\\") && !filePath.Contains("\\bin\\"))
                    fileList.Add(filePath);
            }

            // 获取当前文件夹下的所有子文件夹路径
            string[] subfolders = Directory.GetDirectories(folderPath);
            foreach (string subfolder in subfolders)
            {
                fileList.AddRange(GetAllFilePaths(subfolder, fileExtension)); // 递归调用，处理子文件夹
            }
            return fileList;
        }

        /// <summary>
        /// 复制文件到指定位置，并替换关键词
        /// </summary>
        /// <param name="sourceFilePath"></param>
        /// <param name="destinationFilePath"></param>
        /// <param name="replaceString"></param>
        private void CopyReplaceFile(string sourceFilePath, string destinationFilePath, string replaceString)
        {
            string directoryPath = Path.GetDirectoryName(destinationFilePath);

            if (!string.IsNullOrEmpty(directoryPath) && !Directory.Exists(directoryPath))
            {
                Directory.CreateDirectory(directoryPath);
            }
            Encoding sourceEncoding = DetectFileEncoding(sourceFilePath);
            // 将源文件复制到目标位置，并用新的文本内容替换关键词
            using (StreamReader reader = new StreamReader(sourceFilePath, sourceEncoding))
            using (StreamWriter writer = new StreamWriter(destinationFilePath, false, Encoding.UTF8))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    line = line.Replace("KeXin", replaceString);
                    writer.WriteLine(line);
                }
            }
        }

        public static Encoding DetectFileEncoding(string filePath)
        {
            // 读取文件的字节序标记(BOM)来判断编码
            byte[] buffer = new byte[4];
            using (FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                file.Read(buffer, 0, 4);
                file.Close();
            }

            if (buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf)
                return Encoding.UTF8;
            else if (buffer[0] == 0xff && buffer[1] == 0xfe)
                return Encoding.Unicode;
            else if (buffer[0] == 0xfe && buffer[1] == 0xff)
                return Encoding.BigEndianUnicode;
            else if (buffer[0] == 0 && buffer[1] == 0 && buffer[2] == 0xfe && buffer[3] == 0xff)
                return Encoding.UTF32;
            else
                return Encoding.Default; // 系统默认编码
        }


    }
}
